﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace Test_2D
{
    public partial class FrameForm : WeifenLuo.WinFormsUI.Docking.DockContent
    {
        public FrameForm()
        {
            InitializeComponent();
            addFrame(80);       //初始化出80个帧
        }
        private event Frame_Change ChangeFrame;     //切换帧，此时要更新EditForm中的画布
        public event Frame_Change Change
        {
            add 
            {
                if (ChangeFrame != null)
                    ChangeFrame -= (Frame_Change)(ChangeFrame.GetInvocationList())[0];//可能会有多个EditForm，故先要清除上一个的事件
                ChangeFrame += value;     
            }
            remove { }
        }
        Animation animation;
        public Animation Animation
        {
            //get { return animation; }
            set { this.animation = value; }
        }

        FrameData frameData;
        public FrameData FrameDate
        {
            set 
            { 
                this.frameData = value;
                frame_Click(cur_frame);     //在文件打开时，相当于点击了此帧
                label当前帧.Text = cur_frame.ToString();        ////////////!!!!!!!!!!!!!!!!!!!!/
            }
        }
        private int cur_timeLine
        {
            get { return frameData.TimeLineIndex; }
            set { frameData.TimeLineIndex = value; }
        }
        private int cur_frame
        {
            get { return frameData.FrameIndex; }
            set { frameData.FrameIndex = value; label当前帧.Text = cur_frame.ToString(); }   ////////////!!!!!!!!!!!!!!!!!!!!/
        }

        TimeLine timeLine
        {
            get { return animation.TimeLines[cur_timeLine]; }
        }
        Frame frame;

        /// <summary>
        /// 判断FrameForm中的当前帧是否为关键帧
        /// </summary>
        public bool IsKeyFrame
        {
            get { return isKeyFrame(cur_frame); }
        }

        int frame_index = 1;        //用来控制帧的标号
        Point frame_start = new Point(0, 5);
        Point frame_offest = new Point(15, 0);

        private void addFrame(int count)
        {
            for (int i = 0; i < count; ++i)
            {
                Label lb = new Label();
                lb.AutoSize = true;
                lb.ContextMenuStrip = this.frameMenuStrip;
                lb.Location = frame_start;
                lb.Text = frame_index.ToString();
                lb.MouseDown += new System.Windows.Forms.MouseEventHandler(this.frame_MouseDown);
                this.panel3.Controls.Add(lb);
                frame_index++;
                frame_start.Offset(frame_offest);
            }
        }
        //时间轴的横向滚动条滚动到最后时自动增加帧数
        private void panel3_Scroll(object sender, ScrollEventArgs e)
        {
            Panel pl = (Panel)sender;
            if (pl.HorizontalScroll.Value == pl.HorizontalScroll.Maximum - pl.HorizontalScroll.LargeChange + 1)
            {
                frame_start = panel3.Controls[panel3.Controls.Count - 1].Location;
                frame_start.Offset(frame_offest);
                addFrame(10);   //增加十帧
            }
        }
        //得到自定义的帧数
        private void textBox2_TextChanged(object sender, EventArgs e)
        {
            if (textBox2.Text == "")
                return;

            panel3.Controls.Clear();
            frame_index = 1;
            frame_start = new Point(0, 5);
            addFrame(int.Parse(textBox2.Text));
        }

        /// <summary>
        /// 帧操作主函数
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void frame_MouseDown(object sender, MouseEventArgs e)
        {
            Label label = (Label)sender;            /////////////////////////

            cur_timeLine = 0;           //获得当前时间轴号   ///模拟第一层
            cur_frame = int.Parse(label.Text.ToString()) - 1;//当前帧号=帧的标号-1

            label点击帧.Text = cur_frame.ToString(); ///////////////////////!!!!!!!!!!!!!!!!!!!!!!!!

            if (e.Button == MouseButtons.Left)
            {
                frame_Click(cur_frame);     //点击左键，更新画布
            }
            else if (e.Button == MouseButtons.Right)
            {
                this.frameMenuStrip.Show(label, e.Location);    //点击右键，显示菜单

                if (cur_frame >= timeLine.Frames.Count)
                    删除帧ToolStripMenuItem.Enabled = false;
                else
                    删除帧ToolStripMenuItem.Enabled = true;

                if (isKeyFrame(cur_frame))
                {
                    插入关键帧ToolStripMenuItem.Enabled = false;

                    int nextKey = getNextKey(cur_frame);
                    if (nextKey != -1 && !timeLine.Frames[cur_frame].IsEmpty && !timeLine.Frames[nextKey].IsEmpty 
                        && timeLine.Frames[cur_frame].Tween == null)
                        动画补间ToolStripMenuItem.Enabled = true;   //有下一个关键帧且这两个帧都不是空白的且没有补间，就可创建补间
                }
                else
                {
                    插入关键帧ToolStripMenuItem.Enabled = true;
                    动画补间ToolStripMenuItem.Enabled = false;
                }
            }
        }

        /// <summary>
        /// 在画布上显示帧的内容
        /// </summary>
        /// <param name="frame_index"></param>
        public void frame_Click(int frame_index)
        {
            FrameState fmst = this.getFrameState(frame_index); //获取帧的状态
            //不做任何事
            if (fmst == FrameState.INEXISTENCE)
                return;     
            //向前寻找关键帧
            else if (fmst == FrameState.NULL)
            {
                frame_Click(getPreKey(frame_index));
            }
            //显示关键帧的内容
            else if (fmst == FrameState.KEY_NEMPTY || fmst == FrameState.KEY_EMPTY)// || fmst == FrameState.NKEY_NEMPTY)
            {
                //关键帧是补间帧，并且此关键帧的帧号与当前帧号不同时，根据补间算法算出当前帧号的运动元
                if (timeLine.Frames[frame_index].Tween != null && frame_index != cur_frame)     
                {
                    timeLine.Frames[cur_frame] = new Frame();
                    timeLine.Frames[cur_frame].Motions.Add(
                        timeLine.Frames[frame_index].Tween.getTweenMotion(cur_frame - frame_index));

                    ChangeFrame(cur_timeLine, cur_frame);
                    timeLine.Frames[cur_frame] = null;   
                }
                //关键帧不为补间帧或关键帧的帧号就是当前帧号时，显示此帧的内容
                else
                {
                    cur_frame = frame_index;        //当前帧改变
                    ChangeFrame(cur_timeLine, cur_frame);
                }
            }
        }

        private void 插入关键帧ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            insertKeyFrame(cur_frame, false);
            ChangeFrame(cur_timeLine, cur_frame);
        }

        private void 插入空白关键帧ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            insertKeyFrame(cur_frame, true);
            ChangeFrame(cur_timeLine, cur_frame);
            
        }

        private void 删除帧ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //如果下个帧存在且不是关键帧(即null)，则删除当前帧的下个帧
            if (cur_frame + 1 < timeLine.Frames.Count && !isKeyFrame(cur_frame + 1))
            {
                timeLine.Frames.RemoveAt(cur_frame + 1);    //删除下个帧
                frame_Click(--cur_frame);       //更新当前帧
            }
            //当下一个帧不存在，或下个帧为关键帧时，则删除当前帧(关键帧||null)
            else
            {
                //如果此帧是关键帧，则继续判断是否属于补间动画的最后一帧(如是，则还要删除补间)
                if (isKeyFrame(cur_frame))
                {
                    int preKey = getPreKey(cur_frame);
                    if (preKey != -1 && timeLine.Frames[preKey].Tween != null)
                    {
                        timeLine.Frames[preKey].Tween = null;  //删除补间
                    }
                }

                timeLine.Frames.RemoveAt(cur_frame);    //删除此帧

                if (cur_frame == 0)
                    ChangeFrame(cur_timeLine, -1);   //删除了一个时间轴的最后一帧(即第一帧),清空画布
                else
                    frame_Click(--cur_frame);   //删除后当前时间轴后退一帧，更新画布(相当于左键单击了此帧)
            }

            /*
            //如果此帧不是关键帧，直接删除之
            if (!isKeyFrame(cur_frame))
                timeLine.Frames.RemoveAt(cur_frame);
            //
            else if (cur_frame + 1 < timeLine.Frames.Count && isKeyFrame(cur_frame + 1))

            {
                timeLine.Frames.RemoveAt(cur_frame);
            }

            else if (cur_frame + 1 >= timeLine.Frames.Count || isKeyFrame(cur_frame + 1))
            {
                //当下一帧超出范围或下一帧为关键帧时，删除
            }*/

        }

        private void 动画补间ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            动画补间ToolStripMenuItem.Enabled = false;

            int nextkey = getNextKey(cur_frame);    //执行此函数时已经判断过是两个都为非空关键帧


            Tween tween = new Tween(timeLine.Frames[cur_frame], timeLine.Frames[nextkey], timeLine);

            timeLine.Frames[cur_frame].Tween = tween;
            /*
            if (timeLine.Frames[cur_frame].Motions.Count == 0 && nextkey == -1 &&
                timeLine.Frames[nextkey].Motions.Count == 0)
            {
                MessageBox.Show("Can't Tween");
                return;
            }
            
            Motion start_mot = timeLine.Frames[cur_frame].Motions[0];

            Point startP = new Point(start_mot.Location.X, start_mot.Location.Y);
            Point endP = timeLine.Frames[getNextKey(cur_frame)].Motions[0].Location;

            int inc_x = (endP.X - startP.X) / (nextkey - cur_frame);    //运动元在每一帧x方向上的增量
            int inc_y = (endP.Y - startP.Y) / (nextkey - cur_frame);    //运动元在每一帧y方向上的增量

            int cur_act = start_mot.Act;    //起始动作号
            for (int i = cur_frame + 1; i < nextkey; ++i)
            {
                cur_act++;

                if (cur_act > start_mot.Component.ActCount)
                    cur_act = 1;

                startP.Offset(inc_x, inc_y);

                //if (timeLine.Frames[i] == null)
                timeLine.Frames[i] = new Frame();

                timeLine.Frames[i].Motions.Add(
                    new Motion(start_mot.Component, cur_act, new Point(startP.X, startP.Y), start_mot.Size));
            }*/
        }

        //获取帧的状态
        //INEXISTENCE   帧不存在，没有为其分配空间
        //NULL          帧分配了空间，但指向null且key值为false
        //NKEY_NEMPTY   帧不为关键帧，有运动元
        //KEY_NEMPTY    帧为关键帧，有运动元
        //KEY_EMPTY     帧分配了空间，但指向null且key值为true
        //UNKNOWN       未知，一般不可能出现此情况
        enum FrameState { INEXISTENCE, NULL, NKEY_NEMPTY, KEY_NEMPTY, KEY_EMPTY, UNKNOWN }

        /// <summary>
        /// 获取指定帧的状态
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        private FrameState getFrameState(int index)
        {
            if (index > timeLine.Frames.Count - 1 || index == -1)
                return FrameState.INEXISTENCE;              //帧号超出范围
            if (timeLine.Frames[index] == null)
                return FrameState.NULL;                     //帧指向null

            string str = "";
            str += timeLine.Frames[index].IsKey ? 1 : 0;
            str += timeLine.Frames[index].IsEmpty ? 1 : 0;

            switch (int.Parse(str))
            {
                case 00: return FrameState.NKEY_NEMPTY;     //不是关键字，不是空的
                case 10: return FrameState.KEY_NEMPTY;      //是关键字，不是空的
                case 11: return FrameState.KEY_EMPTY;       //是关键字，是空的
                default: return FrameState.UNKNOWN;         //无法判断
            }
        }

        /// <summary>
        /// 判断index是否为关键帧
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        private bool isKeyFrame(int index)
        {
            FrameState tmp_fs = getFrameState(index);
            if (tmp_fs == FrameState.KEY_EMPTY || tmp_fs == FrameState.KEY_NEMPTY)
                return true;
            else
                return false;
        }
        
        /// <summary>
        /// 在index处插入关键帧
        /// </summary>
        /// <param name="index"></param>
        /// <param name="isEmpty">true表示插入空白关键帧</param>
        private void insertKeyFrame(int index, bool isEmpty)
        {
            if (!isKeyFrame(index))
            {
                int prekey = getPreKey(index);
                if (prekey != -1)
                {
                    int max = timeLine.Frames.Count;    //当前时间轴的帧个数
                    if (index > max - 1)    //如果当前帧在帧的范围之外，补充null
                    {
                        for (int i = max; i <= index; ++i)
                            timeLine.Frames.Add(null);
                    }
          
                    /*for (int i = prekey + 1; i < index; ++i)
                        timeLine.Frames.Add(null);*/

                    //timeLine.Frames.Add(new Frame());       //添加index处的帧

                    timeLine.Frames[index] = new Frame();   //将index处的帧转为关键帧
                    timeLine.Frames[index].IsKey = true;    //设置为关键帧

                    if (!isEmpty)
                    {
                        foreach (Motion mot in timeLine.Frames[prekey].Motions) //复制前一个关键帧的运动元
                        {
                            timeLine.Frames[index].Motions.Add(new Motion(mot));
                        }
                    }
                }
                else    //此时可以确定时间轴为空
                {
                    //首先在第一帧添加空白关键帧
                    timeLine.Frames.Add(new Frame());   //添加第一帧
                    timeLine.Frames[0].IsKey = true;    //设置第一帧为关键帧

                    if (index != 0)         //如果帧不是第一帧，则添加index处的帧
                    {
                        for (int i = 1; i < index; ++i)
                            timeLine.Frames.Add(null);

                        timeLine.Frames.Add(new Frame());   //添加index处的帧
                        timeLine.Frames[index].IsKey = true;    //设置index处的帧为关键帧
                    }
                }

                cur_frame = index;  //当前帧为新插入的帧

                /*
                int max = timeLine.Frames.Count - 1;    //当前时间轴帧索引的最大值
                if (index > max)
                {
                    for (int i = 0; i < index - max; ++i)
                        timeLine.Frames.Add(null);
                }

                if (timeLine.Frames[index] == null)
                {
                    timeLine.Frames[index] = new Frame();
                }
                timeLine.Frames[index].IsKey = true;    //设置为空白关键帧KEY_EMPTY 

                //如果有前一个关键帧且非空，则将其下的运动元复制给新的关键帧
                int prekey = getPreKey(index);
                if (prekey != -1 && !timeLine.Frames[prekey].IsEmpty)
                {
                    foreach (Motion mot in timeLine.Frames[prekey].Motions)
                    {
                        timeLine.Frames[index].Motions.Add(new Motion(mot));
                    }
                }
                 * */
            }
        }

        //获得前一个关键帧的索引
        private int getPreKey(int index)
        {
            for (int i = index - 1; i >= 0; --i)
            {
                FrameState tmp_fs = getFrameState(i);
                if (tmp_fs == FrameState.KEY_EMPTY || tmp_fs == FrameState.KEY_NEMPTY)
                    return i;
            }
                /*
            for (int i = index - 1; i >= 0; --i)
            {
                if (timeLine.Frames[i] == null)
                    continue;

                if (timeLine.Frames[i].IsKey)
                    return i;
            }
                 * */
            return -1;
        }
        //获得后一个关键帧的索引
        private int getNextKey(int index)
        {
            for (int i = index + 1; i < timeLine.Frames.Count; ++i)
            {
                FrameState tmp_fs = getFrameState(i);
                if (tmp_fs == FrameState.KEY_EMPTY || tmp_fs == FrameState.KEY_NEMPTY)
                    return i;
            }
            /*
            for (int i = index + 1; i < timeLine.Frames.Count; ++i)
            {
                if (timeLine.Frames[i] == null)
                    continue;

                if (timeLine.Frames[i].IsKey)
                    return i;
            }*/
            return -1;
        }

        //beta,清除时间轴的数据
        public void Clear()
        {
            animation = null;
        }
    }
}
